/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package processManagement;

import UI.MainInterface;
import deviceManagement.DeviceManager;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import memoryManagement.*;

/**
 *
 * @author Administrator
 */
public class PCT {                              //进程表 process table ，在此处代替执行进程管理器的功能

    int length = 10;      //本系统最多有10个进程块，即10个进程
    public int T = 5;      //一个时间片大小，默认为5秒
    Process[] allProcess = new Process[10];//系统所能容纳的所有进程
    public LinkedList<Process> carry = new LinkedList<>(); //执行队列，只能有一个进程在运行，初始时为空
    public LinkedList<Process> ready = new LinkedList<>(); //就绪队列
    public LinkedList<Process> block = new LinkedList<>(); //等待队列
    public ArrayList<String> log = new ArrayList<>(); //日志
    int autoID = 1;     //自动递增的进程ID
    Random rd = new Random();

    public PCT() {
        for (int i = 0; i < 10; i++) {
            allProcess[i] = new Process(i);
            allProcess[i].ID = i;
            allProcess[i].status = 4; //表示该进程可用
        }
        allProcess[0].status = 0;
        carry.add(allProcess[0]);      //  0号进程为闲逛进程
        log.add("进程管理器初始化完毕");
    }

    public boolean createProcess(mem m, DeviceManager d) {//创建进程
        /*if((carry.size()+block.size()+wait.size())>=10){
         log.add("系统进程已满，新进程创建失败");
         return false;
         }*/
        Process process = null;
        for (int i = 0; i < 10; i++) {
            if (allProcess[i].status == 4) {
                process = allProcess[i]; //获取可用进程，status=4
            }
        }
        if (process == null) {
            log.add("系统进程已满，新进程创建失败");
            return false;
        }
        //Process process = new Process(autoID++);
        for (int i = 1; i < 3; i++) {
            process.device[i] = rd.nextInt(3);//随机生成进程所需设备
        }
        process.device[0] = rd.nextInt(2);
        process.size = rd.nextInt(255) + 1;//随机生成进程所需内存大小1~511
        process.priority = rd.nextInt(4);//优先级0~3
        process.submit_time = MainInterface.getCurrentTime(); //进程生成时间，到时记得改为系统时间
        process.require_time = rd.nextInt(100); //进程完成所需时间
        if (m.create(process.ID, process.size) && d.isAllowProcess(process)) { //是否给进程分配内存及设备
            process.status = 1;//放到就绪队列
            ready.add(process);
            log.add(process.ID + "号进程创建成功，添加到就绪队列");
        } else {
            //process.status = 2;
            blockProcess(process, m, d);//分配内存或空间失败，阻塞该进程
            log.add(process.ID + "号进程创建成功，添加到阻塞队列");
            //block.add(process); //未获取设备或内存空间，放到等待队列
        }
        return true;
    }

    public void destoryProcess(Process p, mem m, DeviceManager d) {  //销毁进程
        m.release(p.ID);//回收内存
        d.Recover(p);//回收设备
        if (carry.contains(p)) {
            carry.remove(p);
        }
        if (ready.contains(p)) {
            ready.remove(p);
        }
        if (block.contains(p)) {
            block.remove(p);
        }
        p.status = 4;
        p.duration_time = 0;
        p.execute_time = 0;
        p.finish_time = 0;
        p.submit_time = 0;
        p.require_time = 0;
        log.add(p.ID + "号进程执行完毕，进行销毁");
    }

    public void blockProcess(Process p, mem m, DeviceManager d) {    //阻塞进程
        //m.Refresh(p);//内存刷新，是否回收内存由内存管理决定
        d.Refresh(p);//设备刷新，是否回收内存由设备管理决定
        if (carry.contains(p)) {
            carry.remove(p);
        }
        if (ready.contains(p)) {
            ready.remove(p);
        }
        if (block.contains(p)) {
            block.remove(p);
        }
        p.status = 2;//设为阻塞态
        block.add(p);
        log.add(p.ID + "号进程阻塞");
        scheduleProcess(m, d);
    }

    public void awakeProcess(Process p, mem m, DeviceManager d) {  //唤醒进程
        if (block.contains(p)) {
            block.remove(p);
        }
        if (/*m.isAllowProcess(p) &&*/ d.isAllowProcess(p)) { //是否给进程分配
            //System.out.println(p.ID+"号进程唤醒成功");
            p.status = 1;//放到就绪队列
            ready.add(p);
            log.add(p.ID + "号进程解除阻塞，添加到就绪队列");
        } else {
            //System.out.println(p.ID+"号进程唤醒失败");
            p.status = 2;
            block.add(p); //未获取设备或内存空间，放到等待队列
        }
    }

    public void scheduleProcess( mem m, DeviceManager d) { //进程调度
        Process process1;
        Process process2;
        process2 = carry.peek();//弹出执行完时间片的进程
        if((process2.execute_time + T) >= process2.require_time || ready.size()!=0){
        //{
        process2 = carry.poll();
        if (ready.size() != 0) {
            process1 = ready.poll();//从就绪队列中取出一个待执行进程
        } else {
            process1 = allProcess[0];//就绪队列为空，取闲逛进程
        }
        
        if ((process2.execute_time + T) >= process2.require_time) { //进程执行完成,销毁进程
            if(process2.ID!=0)//非闲逛进程
            destoryProcess(process2, m, d);
        } else {
            process2.execute_time += T;//进程尚未执行完，替换到就绪队列
            process2.status = 1;
            ready.add(process2);
            log.add(process2.ID + "号进程切换到就绪态");
        }

        process1.status = 0;
        carry.add(process1);
        log.add(process1.ID + "号进程切换到执行态");
        }

        int size = block.size();
        for (int i = 0; i < size; i++) {
            //System.out.println("尝试唤醒"+block.peek().ID);
            awakeProcess(block.poll(), m, d);//检查阻塞队列是否有进程可换为就绪态
        }
    }

}
